package com.cskaoyan.wordmemorize.service.impl;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cskaoyan.wordmemorize.common.exception.BusinessException;
import com.cskaoyan.wordmemorize.converter.ReviewConverter;
import com.cskaoyan.wordmemorize.dao.entity.*;
import com.cskaoyan.wordmemorize.dao.mapper.*;
import com.cskaoyan.wordmemorize.dto.admin.PageDTO;
import com.cskaoyan.wordmemorize.dto.app.UserCheckinDTO;
import com.cskaoyan.wordmemorize.dto.app.UserCheckinStatisticsDTO;
import com.cskaoyan.wordmemorize.request.PageRequest;
import com.cskaoyan.wordmemorize.request.UserCheckinCommand;
import com.cskaoyan.wordmemorize.service.UserCheckinService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.List;

/**
 * @author 顾海龙
 * @version 1.0
 */
@Service
public class UserCheckinServiceImpl implements UserCheckinService {

    //操作统计表的mapper
    @Autowired
    UserCheckinStatisticsMapper userCheckinStatisticsMapper;

    //操作打卡表的mapper
    @Autowired
    UserCheckinMapper userCheckinMapper;

    //操作用户表，如修改的值有等级名称，等级值，升级时间。
    @Autowired
    UserMapper userMapper;

    //操作单词上限变化记录的表，如签到增加一个单词上限，升级解锁权限增加单词上限等
    @Autowired
    UserVocBoundLogMapper userVocBoundLogMapper;

    //操作单词上限的统计表，
    @Autowired
    UserVocBoundStatisticsMapper userVocBoundStatisticsMapper;

    //查询等级表的mapper
    @Autowired
    LevelMapper levelMapper;
    //转换器
    @Autowired
    ReviewConverter reviewConverter;

    // APP端下载打卡数据(如果分页参数没有传的话，就返回所有打卡数据)
    @Override
    public PageDTO<UserCheckinDTO> getCheckInData(PageRequest pageRequest, Long userId) {
        PageDTO<UserCheckinDTO> pageDTO;
        QueryWrapper<UserCheckinDO> userCheckinDOQueryWrapper = new QueryWrapper<>();
        userCheckinDOQueryWrapper.eq("user_id", userId);
        if (pageRequest.getPageNum() != null && pageRequest.getPageNum() > 0) {
            //分页查询数据
            Page<UserCheckinDO> userCheckinDOPage = new Page<>(pageRequest.getPageNum(), pageRequest.getCount());
            Page<UserCheckinDO> userCheckinDOPageList = userCheckinMapper.selectPage(userCheckinDOPage, userCheckinDOQueryWrapper);
            List<UserCheckinDO> records = userCheckinDOPageList.getRecords();
            pageDTO = reviewConverter.userCheckinPage2PageDTO(records, userCheckinDOPageList.getTotal());
        } else {
            //查询所有数据
            List<UserCheckinDO> userCheckinDOS = userCheckinMapper.selectList(userCheckinDOQueryWrapper);
            pageDTO = reviewConverter.userCheckinPage2PageDTO(userCheckinDOS, (long) userCheckinDOS.size());
        }
        return pageDTO;
    }

    //需要先需要修改user表中的签到天数这些数据，修改完数据还需要判断是否满足升级条件，
    // 满足条件还需要修改等级，修改对应的特权和单词上限。涉及的表有
    // level：等级升级对应的信息，如升级需要什么条件。
    // user_voc_bound_statistics表:用户的单词上限统计信息，如支付单词上限，单词总数上限等。
    // user_voc_bund_log表：用户单词上限变更的记录，签到增加一个单词上限，升级解锁权限增加单词上限。
    // user用户表：记录用户的信息，如果升级需要修改的值有等级名称，等级值，升级时间。
    // user_checkin_statistics：记录用户签到的总数，连续签到的总数，历史最大签到数，最大签到起始日期，结束日期等。
    // user_checkin：记录用户的打卡信息，不论是补签还是正常打卡都需要计入其中。

    // APP端打卡
    @Override
    public UserCheckinStatisticsDTO checkin(UserCheckinCommand command) {
        //查询前一天是否有打卡记录
        LocalDate localDate = LocalDate.now().minusDays(1);
        QueryWrapper<UserCheckinDO> userCheckinDOQueryWrapper = new QueryWrapper<>();
        userCheckinDOQueryWrapper.eq("user_id", command.getUserId())
                .eq("sign_date", localDate);
        UserCheckinDO userCheckinDO1 = userCheckinMapper.selectOne(userCheckinDOQueryWrapper);
        //雪花算法工具类对象
        Snowflake snowflake = IdUtil.getSnowflake(1, 1);
        //先检查一下账号是否连续签到过。
        QueryWrapper<UserCheckinStatisticsDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", command.getUserId());
        UserCheckinStatisticsDO userCheckinStatisticsDO = userCheckinStatisticsMapper.selectOne(queryWrapper);
        //更新最新的数据
        if (userCheckinDO1 == null){
            userCheckinStatisticsDO.setCurContinuousDays(0);
            userCheckinStatisticsDO.setCurContinuousStartDate(command.getSignDate());
        }
        QueryWrapper<UserCheckinDO> userCheckinDOQueryWrapper1 = new QueryWrapper<>();
        userCheckinDOQueryWrapper1.eq("user_id", command.getUserId());
        //查询当天是否打卡
        UserCheckinDO userCheckinDO2 = userCheckinMapper.selectOne(userCheckinDOQueryWrapper1);
        if (userCheckinStatisticsDO.getCurContinuousDays() == 0 || userCheckinDO1 == null) {
            //当前签到为连续签到第一天，直接插入数据，段号生成使用雪花算法
            UserCheckinDO userCheckinDO = new UserCheckinDO();
            userCheckinDO.setUserId(Long.parseLong(command.getUserId()));
            userCheckinDO.setSignDate(command.getSignDate());
            userCheckinDO.setStickNo(snowflake.nextId());
            userCheckinDO.setType(1);
            if (userCheckinDO2 == null){
                userCheckinMapper.insert(userCheckinDO);
            }
        }
        else {
            //表示是连续签到
            UserCheckinDO userCheckinDO = new UserCheckinDO();
            userCheckinDO.setUserId(Long.parseLong(command.getUserId()));
            userCheckinDO.setSignDate(LocalDate.now());
            //赋值为相同的签到段
            userCheckinDO.setStickNo(userCheckinDO1.getStickNo());
            userCheckinDO.setType(1);
            if (userCheckinDO2 == null){
                userCheckinMapper.insert(userCheckinDO);
            }
        }
        //查询出签到记录表，判断数据是否需要修改。
        QueryWrapper<UserCheckinStatisticsDO> userCheckinStatisticsDOQueryWrapper = new QueryWrapper<>();
        userCheckinStatisticsDOQueryWrapper.eq("user_id", command.getUserId());
        UserCheckinStatisticsDO userCheckinStatisticsDO1 = userCheckinStatisticsMapper.selectOne(userCheckinStatisticsDOQueryWrapper);
        //修改总签到天数+1(无论是第一次签到还是不是第一次签到都需要要增加)
        userCheckinStatisticsDO1.setTotalDays(userCheckinStatisticsDO1.getTotalDays() + 1);
        if(userCheckinStatisticsDO.getCurContinuousDays() == 0 || userCheckinDO1 == null){
            //修改连续签到起始日期(如果是第一次需要修改)
            userCheckinStatisticsDO1.setCurContinuousStartDate(LocalDate.now());
        }
        //修改当前连续签到天数(通用)
        userCheckinStatisticsDO1.setCurContinuousDays(userCheckinStatisticsDO1.getCurContinuousDays() + 1);
        //判断是否需要修改最大连续签到天数
        if (userCheckinStatisticsDO1.getMaxContinuousDays() == 0) {
            userCheckinStatisticsDO1.setMaxContinuousDays(1);
            userCheckinStatisticsDO1.setMaxContinuousStartDate(command.getSignDate());
        }else if (userCheckinStatisticsDO1.getMaxContinuousDays() < userCheckinStatisticsDO1.getCurContinuousDays()){
            //当前签到天数大于了历史最大签到天数
            userCheckinStatisticsDO1.setMaxContinuousDays(userCheckinStatisticsDO1.getCurContinuousDays());
            userCheckinStatisticsDO1.setMaxContinuousStartDate(userCheckinStatisticsDO1.getCurContinuousStartDate());
        }
        //将表中数据更新
        userCheckinStatisticsMapper.updateById(userCheckinStatisticsDO1);
        //获取当前用户的信息
        UserDO userDO = userMapper.selectById(command.getUserId());
        Integer levelValue = userDO.getLevelValue();
        QueryWrapper<LevelDO> levelMapperQueryWrapper = new QueryWrapper<>();
        levelMapperQueryWrapper.eq("level_value", levelValue);
        LevelDO levelDO = levelMapper.selectOne(levelMapperQueryWrapper);
        if (levelDO.getCheckInType() == 2) {
            //累计签到升级
            if (userCheckinStatisticsDO1.getTotalDays() >= levelDO.getCheckInDays()) {
                //用户需要升级(修改用户的等级值，等级名，升级时间)
                userDO.setLevelValue(userDO.getLevelValue() + 1);
                userDO.setLevelName("LVL" + (userDO.getLevelValue()));
                userDO.setLevelDate(LocalDate.now());
                userMapper.updateById(userDO);
            }
        } else {
            //连续签到升级(需要从6级升到7级的时间开始算连续签到，满足条件时才能进行升级)
            if (userDO.getLevelValue() == 7){
                if ((userCheckinStatisticsDO1.getCurContinuousDays() >= levelDO.getCheckInDays()) && (ChronoUnit.DAYS.between(userDO.getLevelDate(),command.getSignDate())) >= levelDO.getCheckInDays()){
                    //用户需要升级
                    userDO.setLevelValue(userDO.getLevelValue() + 1);
                    userDO.setLevelName("LVL" + (userDO.getLevelValue()));
                    userDO.setLevelDate(LocalDate.now());
                    userMapper.updateById(userDO);
                }
            }
            else {
                if ((userCheckinStatisticsDO1.getCurContinuousDays() >= levelDO.getCheckInDays()) && (ChronoUnit.DAYS.between(userDO.getLevelDate(),command.getSignDate())) >= 3) {
                    //用户需要升级
                    userDO.setLevelValue(userDO.getLevelValue() + 1);
                    userDO.setLevelName("LVL" + (userDO.getLevelValue()));
                    userDO.setLevelDate(LocalDate.now());
                    userMapper.updateById(userDO);
                }
            }
        }
        //单词上限增加
        if (userCheckinStatisticsDO1.getCurContinuousDays() >= 10) {
            //连续天数大于等于10天，增加免费单词上限为10
            QueryWrapper<UserVocBoundStatisticsDO> userVocBoundStatisticsDOQueryWrapper = new QueryWrapper<>();
            userVocBoundStatisticsDOQueryWrapper.eq("user_id", command.getUserId());
            UserVocBoundStatisticsDO userVocBoundStatisticsDO = userVocBoundStatisticsMapper.selectOne(userVocBoundStatisticsDOQueryWrapper);
            userVocBoundStatisticsDO.setFree(userVocBoundStatisticsDO.getFree() + 10);
            userVocBoundStatisticsDO.setTotal(userVocBoundStatisticsDO.getTotal() + 10);
            userVocBoundStatisticsDO.setAvailable(userVocBoundStatisticsDO.getAvailable() + 10);
            userVocBoundStatisticsMapper.updateById(userVocBoundStatisticsDO);
            //写入记录
            UserVocBoundLogDO userVocBoundLogDO = new UserVocBoundLogDO();
            userVocBoundLogDO.setUserId(Long.parseLong(command.getUserId()));
            userVocBoundLogDO.setLogDate(LocalDate.now());
            userVocBoundLogDO.setType(2);
            userVocBoundLogDO.setCount(10);
            userVocBoundLogDO.setDescription("签到增加10个单词上限");
            userVocBoundLogMapper.insert(userVocBoundLogDO);
        } else {
            //连续天数小于10，增加免费单词上限为当前连续签到天数
            QueryWrapper<UserVocBoundStatisticsDO> userVocBoundStatisticsDOQueryWrapper = new QueryWrapper<>();
            userVocBoundStatisticsDOQueryWrapper.eq("user_id", command.getUserId());
            UserVocBoundStatisticsDO userVocBoundStatisticsDO = userVocBoundStatisticsMapper.selectOne(userVocBoundStatisticsDOQueryWrapper);
            userVocBoundStatisticsDO.setFree(userVocBoundStatisticsDO.getFree() + userCheckinStatisticsDO1.getCurContinuousDays());
            userVocBoundStatisticsDO.setTotal(userVocBoundStatisticsDO.getTotal() + userCheckinStatisticsDO1.getCurContinuousDays());
            userVocBoundStatisticsDO.setAvailable(userVocBoundStatisticsDO.getAvailable() + userCheckinStatisticsDO1.getCurContinuousDays());
            userVocBoundStatisticsMapper.updateById(userVocBoundStatisticsDO);
            //写入记录
            UserVocBoundLogDO userVocBoundLogDO = new UserVocBoundLogDO();
            userVocBoundLogDO.setUserId(Long.parseLong(command.getUserId()));
            userVocBoundLogDO.setLogDate(LocalDate.now());
            userVocBoundLogDO.setType(2);
            userVocBoundLogDO.setCount(userCheckinStatisticsDO1.getCurContinuousDays());
            userVocBoundLogDO.setDescription("签到增加" + userCheckinStatisticsDO1.getCurContinuousDays() + "个单词上限");
            userVocBoundLogMapper.insert(userVocBoundLogDO);
        }
        UserCheckinStatisticsDTO userCheckinStatisticsDTO = reviewConverter.userCheckinStatisticsDO2DTO(userCheckinStatisticsDO1);
        return userCheckinStatisticsDTO;
    }


    // APP端获取用户打卡数据
    @Override
    public UserCheckinStatisticsDTO getUserCheckinStatistics(Long userId) throws BusinessException {
        QueryWrapper<UserCheckinStatisticsDO> statisticsDOQueryWrapper = new QueryWrapper<>();
        statisticsDOQueryWrapper.eq("user_id", userId);
        UserCheckinStatisticsDO userCheckinStatisticsDO = userCheckinStatisticsMapper.selectOne(statisticsDOQueryWrapper);
        UserCheckinStatisticsDTO userCheckinStatisticsDTO = reviewConverter.userCheckinStatisticsDO2DTO(userCheckinStatisticsDO);
        return userCheckinStatisticsDTO;
    }

    //APP端获取用户签到统计数据
    @Override
    public UserCheckinStatisticsDTO getUserContinuousCheckinInfo(Long userId) {
        return null;
    }

    //APP端使用补签卡
    @Override
    public void userResignCard(Long userId) {

    }
}
